package com.gomcarter.frameworks.redis.factory;

import com.gomcarter.frameworks.base.common.JsonMapper;
import com.gomcarter.frameworks.redis.RedisProperties;
import com.gomcarter.frameworks.redis.tool.RedisProxy;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;

public class RedisConnectionBuilder {
    static final Logger logger = LoggerFactory.getLogger(RedisConnectionBuilder.class);

    static Pattern pattern = Pattern.compile("^.+[:]\\d{1,5}\\s*$");

    /**
     * @param proxy      proxy
     * @param properties properties
     */
    public static void of(RedisProxy proxy, RedisProperties properties) {
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();

        //最大空闲数
        poolConfig.setMaxIdle(properties.getMaxIdle());
        poolConfig.setMinIdle(properties.getMinIdle());
        poolConfig.setMaxTotal(properties.getMaxTotal());
        //最大建立连接等待时间
        poolConfig.setMaxWaitMillis(properties.getMaxWait());
        //是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
        poolConfig.setTestOnBorrow(properties.isTestOnBorrow());

        Set<HostAndPort> haps = new HashSet<>();
        for (String hostWithPort : properties.getHostWithPorts()) {
            boolean isIpPort = pattern.matcher(hostWithPort).matches();
            if (!isIpPort) {
                throw new IllegalArgumentException("ip 或 port 不合法");
            }
            String[] ipAndPort = hostWithPort.split(":");

            logger.info("ipAndPort: {}", JsonMapper.buildNonNullMapper().toJson(ipAndPort));
            HostAndPort hap = new HostAndPort(ipAndPort[0], Integer.parseInt(ipAndPort[1]));
            haps.add(hap);
        }

        synchronized (RedisProxy.class) {
            String mode = properties.getMode();
            String password = properties.getPassword();
            int timeout = properties.getConnectionTimeout();
            int maxAttempts = properties.getMaxAttempts();
            int database = properties.getDatabase();
            proxy.setNeedCache(properties.isCache());
            if ("cluster".equals(mode)) {
                proxy.setJedisCluster(new JedisCluster(haps, timeout, timeout, maxAttempts, password, poolConfig));
            } else if ("standalone".equals(mode)) {
                HostAndPort hostAndPort = haps.iterator().next();
                proxy.setJedisPool(new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), timeout, password, database));
            } else {
                logger.error("fail to initialized redis, cause of error mode");
                throw new RuntimeException("fail to initialized redis, cause of error mode");
            }
        }
    }
}
